INTERPN

Overview

The INTERPN function performs multidimensional interpolation on regular or rectilinear grids, estimating values at arbitrary points within a structured 2D data grid. This implementation wraps SciPy’s scipy.interpolate.interpn function, which internally uses the RegularGridInterpolator class.

A rectilinear grid is a rectangular grid where spacing along each axis can be uneven, but the grid points must be strictly ascending along each dimension. Given known data values at these grid points, interpolation estimates values at intermediate locations that fall between the defined grid coordinates. This is particularly useful for working with tabular data, lookup tables, or any scenario where values are known at discrete grid points but needed at arbitrary locations.

The function supports three interpolation methods: - Linear (default): Performs multilinear interpolation by computing weighted averages of the 2^n nearest grid points. For 2D data, this is equivalent to bilinear interpolation. - Nearest: Returns the value of the closest grid point, useful when data represents discrete categories or when speed is prioritized over smoothness. - Splinef2d: Uses a 2D spline approximation via RectBivariateSpline, providing smoother results but only available for 2-dimensional data.

For bilinear interpolation (linear method in 2D), the interpolated value at point (x, y) is computed as:

f(x, y) \approx \frac{1}{(x_2 - x_1)(y_2 - y_1)} \left[ f(x_1, y_1)(x_2 - x)(y_2 - y) + f(x_2, y_1)(x - x_1)(y_2 - y) + f(x_1, y_2)(x_2 - x)(y - y_1) + f(x_2, y_2)(x - x_1)(y - y_1) \right]

where (x_1, y_1), (x_2, y_1), (x_1, y_2), and (x_2, y_2) are the four surrounding grid points.

The function provides boundary handling options: bounds_error controls whether out-of-bounds queries raise an error, and fill_value specifies the value returned for out-of-bounds points when errors are disabled. For more information, see the SciPy interpolation documentation and the interpn source code on GitHub.

This example function is provided as-is without any representation of accuracy.

Excel Usage

=INTERPN(points_x, points_y, values, xi, interpn_method, bounds_error, fill_value)
  • points_x (list[list], required): Column vector of x-coordinates of the grid points
  • points_y (list[list], required): Column vector of y-coordinates of the grid points
  • values (list[list], required): 2D array of data values on the grid
  • xi (list[list], required): Points at which to interpolate data (n_points, 2)
  • interpn_method (str, optional, default: “linear”): Interpolation method
  • bounds_error (bool, optional, default: true): If True, error on out-of-bounds points
  • fill_value (float, optional, default: null): Value for out-of-bounds points if bounds_error is False

Returns (list[list]): 2D list (column vector) of interpolated values, or error message (str) if invalid.

Examples

Example 1: Demo case 1

Inputs:

points_x points_y values xi
0 0 0 1 0.5 0.5
1 1 1 2

Excel formula:

=INTERPN({0;1}, {0;1}, {0,1;1,2}, {0.5,0.5})

Expected output:

Result
1

Example 2: Demo case 2

Inputs:

points_x points_y values xi interpn_method
0 0 1 2 3 0.4 0.6 nearest
1 1 4 5 6
2 2 7 8 9

Excel formula:

=INTERPN({0;1;2}, {0;1;2}, {1,2,3;4,5,6;7,8,9}, {0.4,0.6}, "nearest")

Expected output:

Result
2

Example 3: Demo case 3

Inputs:

points_x points_y values xi interpn_method bounds_error fill_value
0 0 1 2 1.5 1.5 linear false -999
1 1 3 4

Excel formula:

=INTERPN({0;1}, {0;1}, {1,2;3,4}, {1.5,1.5}, "linear", FALSE, -999)

Expected output:

Result
-999

Example 4: Demo case 4

Inputs:

points_x points_y values xi interpn_method bounds_error
0 0 1 2 3 0.5 0.5 linear true
1 1 2 3 4 1.5 1
2 2 3 4 5 2 1.5
3 4 5 6

Excel formula:

=INTERPN({0;1;2;3}, {0;1;2}, {1,2,3;2,3,4;3,4,5;4,5,6}, {0.5,0.5;1.5,1;2,1.5}, "linear", TRUE)

Expected output:

Result
2
3.5
4.5

Python Code

import math
import numpy as np
from scipy.interpolate import interpn as scipy_interpn

def interpn(points_x, points_y, values, xi, interpn_method='linear', bounds_error=True, fill_value=None):
    """
    Multidimensional interpolation on regular grids (2D).

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interpn.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        points_x (list[list]): Column vector of x-coordinates of the grid points
        points_y (list[list]): Column vector of y-coordinates of the grid points
        values (list[list]): 2D array of data values on the grid
        xi (list[list]): Points at which to interpolate data (n_points, 2)
        interpn_method (str, optional): Interpolation method Valid options: Linear, Nearest, Spline 2D. Default is 'linear'.
        bounds_error (bool, optional): If True, error on out-of-bounds points Default is True.
        fill_value (float, optional): Value for out-of-bounds points if bounds_error is False Default is None.

    Returns:
        list[list]: 2D list (column vector) of interpolated values, or error message (str) if invalid.
    """
    def to2d(x):
        return [[x]] if not isinstance(x, list) else x

    def flatten(arr):
        return [item for sublist in arr for item in sublist]

    def validate_numeric_2d(arr, name):
        if not isinstance(arr, list):
            return f"Invalid input: {name} must be a 2D list."
        if not all(isinstance(row, list) for row in arr):
            return f"Invalid input: {name} must be a 2D list."
        flat = flatten(arr)
        if not flat:
            return f"Invalid input: {name} must not be empty."
        for val in flat:
            if not isinstance(val, (int, float)):
                return f"Invalid input: {name} must contain only numeric values."
            if math.isnan(val) or math.isinf(val):
                return f"Invalid input: {name} must contain only finite values."
        return None

    # Normalize inputs
    points_x = to2d(points_x)
    points_y = to2d(points_y)
    values = to2d(values)
    xi = to2d(xi)

    # Validate inputs
    err = validate_numeric_2d(points_x, "points_x")
    if err:
        return err
    err = validate_numeric_2d(points_y, "points_y")
    if err:
        return err
    err = validate_numeric_2d(values, "values")
    if err:
        return err
    err = validate_numeric_2d(xi, "xi")
    if err:
        return err

    # Validate interpn_method
    valid_methods = ['linear', 'nearest', 'splinef2d']
    if not isinstance(interpn_method, str) or interpn_method not in valid_methods:
        return f"Invalid input: interpn_method must be one of {valid_methods}."

    # Validate bounds_error
    if not isinstance(bounds_error, bool):
        return "Invalid input: bounds_error must be a boolean."

    # Validate and set fill_value
    if fill_value is None:
        fill_value = float('nan')
    else:
        if not isinstance(fill_value, (int, float)):
            return "Invalid input: fill_value must be a number."
        fill_value = float(fill_value)

    # Flatten grid coordinates
    points_x_flat = flatten(points_x)
    points_y_flat = flatten(points_y)

    # Check grid monotonicity
    if len(points_x_flat) < 2 or len(points_y_flat) < 2:
        return "Invalid input: grid coordinates must have at least 2 points."

    for i in range(len(points_x_flat) - 1):
        if points_x_flat[i] >= points_x_flat[i + 1]:
            return "Invalid input: points_x must be strictly increasing."

    for i in range(len(points_y_flat) - 1):
        if points_y_flat[i] >= points_y_flat[i + 1]:
            return "Invalid input: points_y must be strictly increasing."

    # Validate values dimensions
    if len(values) != len(points_x_flat):
        return f"Invalid input: values must have {len(points_x_flat)} rows to match points_x."

    for row in values:
        if len(row) != len(points_y_flat):
            return f"Invalid input: each row in values must have {len(points_y_flat)} columns to match points_y."

    # Validate xi dimensions
    for row in xi:
        if len(row) != 2:
            return "Invalid input: each row in xi must have exactly 2 columns [x, y]."

    # Convert to numpy arrays
    try:
        values_arr = np.array(values, dtype=float)
        xi_arr = np.array(xi, dtype=float)
        points = (np.array(points_x_flat, dtype=float), np.array(points_y_flat, dtype=float))
    except Exception as exc:
        return f"Invalid input: unable to convert inputs to arrays: {exc}"

    # Perform interpolation
    try:
        result = scipy_interpn(
            points,
            values_arr,
            xi_arr,
            method=interpn_method,
            bounds_error=bounds_error,
            fill_value=fill_value,
        )
    except Exception as exc:
        return f"scipy.interpolate.interpn error: {exc}"

    # Convert result to 2D list (column vector)
    if not isinstance(result, np.ndarray):
        return "scipy.interpolate.interpn error: unexpected result type."

    result_list = [[float(val)] for val in result.flatten()]

    # Validate result
    for row in result_list:
        for val in row:
            if not isinstance(val, float):
                return "scipy.interpolate.interpn error: non-numeric result."
            # Allow NaN if fill_value is NaN, but not inf
            if math.isinf(val):
                return "scipy.interpolate.interpn error: result contains infinite values."

    return result_list

Online Calculator